/**
 * 防抖工具类
 * 提供通用的防抖功能，防止短时间内重复触发事件
 */
export default class DebounceUtil {
    private static timers: Map<string, any> = new Map();
    private static lastExecuteTimes: Map<string, number> = new Map();

    /**
     * 防抖函数 - 延迟执行，如果在延迟时间内再次触发，则重新计时
     * @param key 唯一标识符，用于区分不同的防抖实例
     * @param func 要执行的函数
     * @param delay 延迟时间（毫秒），默认300ms
     * @returns 防抖后的函数
     */
    static debounce(key: string, func: Function, delay: number = 300): Function {
        return (...args: any[]) => {
            // 清除之前的定时器
            if (this.timers.has(key)) {
                clearTimeout(this.timers.get(key));
            }

            // 设置新的定时器
            const timer = setTimeout(() => {
                func.apply(this, args);
                this.timers.delete(key);
            }, delay);

            this.timers.set(key, timer);
        };
    }

    /**
     * 节流函数 - 限制执行频率，在指定时间内只能执行一次
     * @param key 唯一标识符，用于区分不同的节流实例
     * @param func 要执行的函数
     * @param delay 时间间隔（毫秒），默认300ms
     * @returns 节流后的函数
     */
    static throttle(key: string, func: Function, delay: number = 300): Function {
        return (...args: any[]) => {
            const now = Date.now();
            const lastTime = this.lastExecuteTimes.get(key) || 0;

            if (now - lastTime >= delay) {
                this.lastExecuteTimes.set(key, now);
                func.apply(this, args);
            }
        };
    }

    /**
     * 立即执行一次，然后进入防抖模式
     * @param key 唯一标识符
     * @param func 要执行的函数
     * @param delay 防抖延迟时间（毫秒），默认300ms
     * @returns 防抖后的函数
     */
    static immediate(key: string, func: Function, delay: number = 300): Function {
        return (...args: any[]) => {
            const hasTimer = this.timers.has(key);

            // 如果没有定时器，立即执行
            if (!hasTimer) {
                func.apply(this, args);
            }

            // 清除之前的定时器
            if (hasTimer) {
                clearTimeout(this.timers.get(key));
            }

            // 设置新的定时器
            const timer = setTimeout(() => {
                this.timers.delete(key);
            }, delay);

            this.timers.set(key, timer);
        };
    }

    /**
     * 清除指定key的定时器
     * @param key 唯一标识符
     */
    static clear(key: string): void {
        if (this.timers.has(key)) {
            clearTimeout(this.timers.get(key));
            this.timers.delete(key);
        }
        this.lastExecuteTimes.delete(key);
    }

    /**
     * 清除所有定时器
     */
    static clearAll(): void {
        this.timers.forEach((timer) => {
            clearTimeout(timer);
        });
        this.timers.clear();
        this.lastExecuteTimes.clear();
    }

    /**
     * Vue指令用法的包装器
     * @param element DOM元素
     * @param eventType 事件类型，如 'tap', 'click'
     * @param handler 事件处理函数
     * @param delay 防抖延迟时间
     * @param mode 模式：'debounce' | 'throttle' | 'immediate'
     */
    static bindEvent(
        element: any,
        eventType: string,
        handler: Function,
        delay: number = 300,
        mode: 'debounce' | 'throttle' | 'immediate' = 'debounce'
    ): void {
        const key = `${eventType}_${Date.now()}_${Math.random()}`;

        let wrappedHandler: Function;
        switch (mode) {
            case 'throttle':
                wrappedHandler = this.throttle(key, handler, delay);
                break;
            case 'immediate':
                wrappedHandler = this.immediate(key, handler, delay);
                break;
            default:
                wrappedHandler = this.debounce(key, handler, delay);
                break;
        }

        // 绑定事件
        element.addEventListener(eventType, wrappedHandler);

        // 存储清理函数，用于组件销毁时清理
        if (!element._debounceCleanup) {
            element._debounceCleanup = [];
        }
        element._debounceCleanup.push(() => {
            element.removeEventListener(eventType, wrappedHandler);
            this.clear(key);
        });
    }

    /**
     * 清理元素绑定的所有防抖事件
     * @param element DOM元素
     */
    static unbindElement(element: any): void {
        if (element._debounceCleanup) {
            element._debounceCleanup.forEach((cleanup: Function) => cleanup());
            element._debounceCleanup = [];
        }
    }
}
